#include<stdio.h>
#include<math.h>
#include<stdlib.h>

//Constants

#define maxhid 2 
#define maxnur 20 
#define maxdim 40 
#define maxclass 10 
#define gap 100 
#define upper -5.0 


//Variables
int dim; 
int class_no;
int hid[maxnur+2]; 
//hid[i] has no. of nodes in the ith hidden layer.
//hid[hid[0]+1] has no. of outputs.
int pos,n,count,star,i1;
char file1[13],file2[13],file3[13],cc,bas,ck,norm;
double w[maxhid][maxnur+1][maxnur+1]; 
double maxmin[2]; 
double xvec[maxdim+1]; 
double t[maxclass+1]; 
double delw[maxhid][maxnur+1][maxnur+1]; 
double p,l,lm; 
double err1,averror; 
double out[maxhid+1][maxnur+1];
double th,mul; 
double mult[maxdim]; 
double delmult[maxdim];



//functions
void pick(); 
void initialise();
void makewt(); 
void readwt(); 
void test(); 
void pretrain(); 
void error(); 
void outzero(); 
void dlwzero(); 
void counter(); 
void printwt();
void valel(); 
double err(); 
void maxfind(); 
void balance(); 
void train();
void multinit();

 
 
void main(void)
{

char c;
pick();
initialise();
ck='n';
printf("\n do you wish to train?(y/n):- ");
scanf("%c",&c);fflush(stdin);
if(c=='n') test();
maxfind();
pretrain();
dlwzero();
outzero();
error();
train();
counter();
test();
}

   void pick()
    {
    char c;
    int i,k;
    double a;
    long seed;
	printf("\nenter in the dimentional size:- ");
	scanf("%d",&dim);fflush(stdin);
	printf("\nenter in the no. of classes:- ");
	scanf("%d",&class_no);fflush(stdin);
	printf("\nenter in the no. of hidden layers:- ");
	scanf("%d",&hid[0]);fflush(stdin);
	for(i=1;i<=hid[0];i++)
	 {
	  printf("\nenter in the no. of nurons in layer no.%d:- ",i);
	  scanf("%d",&hid[i]);fflush(stdin);
	 }
	 hid[hid[0]+1]=class_no;pos=hid[0]+1;
	 printf("\n are you satisfied(y/n):- ");
	 scanf("%c",&c);fflush(stdin);
	 if(c=='n') pick();
	 else
	  {
	 star=1;
	 printf("do you want bias?:- ");
	 scanf("%c",&bas);fflush(stdin);
	 if(bas=='y')
	    {
	 star=0;
	 printf("\nenter in seed to randomly initialise bias values:-");
	 scanf("%ld",&seed);fflush(stdin);
	 printf("\nenter in init range -to+a:- ");
	 scanf("%lf",&a);fflush(stdin);
	 xvec[0]=-1.0*a+((double)rand())*2.0*a/((double)RAND_MAX);
	 for(i=1;i<=hid[0];i++)
	 out[i][0]=-1.0*a+((double)rand())*2.0*a/((double)RAND_MAX);
	    }
	   }
	  return;
       }


    void initialise()
    {
     char c;
     FILE *filer;
     int i;
    printf("\ngive in the name of your data file:_ ");
       scanf("%s",file1);fflush(stdin);
       printf("\ngive in the name of your weights file:_ ");
       scanf("%s",file2);fflush(stdin);
       printf("\n give in the name of you mult file");
       scanf("%s",file3);fflush(stdin);
       printf("\n do you want the weights to be initialised random(y/n):- ");
       scanf("%c",&c);fflush(stdin);
       if(c!='y')  readwt();
	else makewt();
	printf("do you want to reset all the multipliers");
	scanf("%c",&c);fflush(stdin);
	if(c=='y') multinit();
	else
	{
	filer=fopen(file3,"r");
	for(i=1;i<=dim;i++)
	fscanf(filer,"%lf",&mult[i]);
	fclose(filer);
	}
	return;
     }

       void readwt()
       {
       int i,j,k;
       FILE *filer;
	   filer=fopen(file2,"r");
	    for(i=star;i<=hid[1];i++)
	     {
	      for(j=star;j<=dim;j++)
	      fscanf(filer,"%lf",&w[0][i][j]);
	     }
	    for(i=1;i<=hid[0];i++)
	     {
	      for(j=star;j<=hid[i+1];j++)
	      {if(i==hid[0] && j==0) continue;
	       for(k=star;k<=hid[i];k++)
	      fscanf(filer,"%lf",&w[i][j][k]);
	     }}
	   fclose(filer);
	   return;
	 }

     void makewt()
	 {
	   double a;
	   long seed;
	   int i,j,k;
	   FILE *filer;
	   printf("\nweights will be initialised between +to-a");
	   printf("\nenter in the value of a:- ");
	   scanf("%lf",&a);fflush(stdin);
	   printf("enter any random int:- ");
	   scanf("%ld",&seed);printf("%ld",seed);fflush(stdin);
	   srand(seed);
	   filer=fopen(file2,"w");
	    for(i=star;i<=hid[1];i++)
	     {
	      for(j=star;j<=dim;j++)
	      {
	       w[0][i][j]=-1.0*a+((double)rand())*2.0*a/((double)RAND_MAX);
	       fprintf(filer,"%lf ",w[0][i][j]);
	      }
	      fprintf(filer,"\n");
	     }
	    for(i=1;i<=hid[0];i++)
	     {
	      for(j=star;j<=hid[i+1];j++)
	      { if(i==hid[0] && j==0) continue;
	       for(k=star;k<=hid[i];k++)
	       {
		w[i][j][k]=-1.0*a+((double)rand())*2.0*a/((double)RAND_MAX);
		fprintf(filer,"%lf ",w[i][j][k]);
	       }
	       fprintf(filer,"\n");
	      }
	      fprintf(filer,"\n");
	     }
	     fclose(filer);
	     return;
	 }

      void maxfind()
      {
      int i;
      FILE *filer;
       filer=fopen(file1,"r");
	 fscanf(filer,"%lf",&maxmin[0]);
	 maxmin[1]=maxmin[0];
	 printf("Read File\n");
	 for(i=2;i<=dim;i++)
	 {
	  fscanf(filer,"%lf",&xvec[i]);
	  if(xvec[i] > maxmin[1]) maxmin[1] = xvec[i];
	  if(xvec[i] < maxmin[0]) maxmin[0] = xvec[i];
	 }

           for(i=1;i<=class_no;i++)
	  fscanf(filer,"%lf",&t[i]);

	  while(!feof(filer))
	 {
	  for(i=1;i<=dim;i++)
	  {
	  fscanf( filer,"%lf",&xvec[i]);
	  if(xvec[i] > maxmin[1]) maxmin[1] = xvec[i];
	  if(xvec[i] < maxmin[0]) maxmin[0] = xvec[i];
	  }
           for(i=1;i<=class_no;i++)
	  fscanf(filer,"%lf",&t[i]);
	 }
	  fclose(filer);
	  return;
     }

     void pretrain()
   {
     printf("\n give in the allowable  mean sqr error:- ");
	 scanf("%lf",&err1);fflush(stdin);
	 printf("\n give in the max no. of iterrations:- ");
	 scanf("%d",&n);fflush(stdin); 
	 printf("\nprevious l=%lf ",l);
     printf("\n give in the learning rate:- ");
	 scanf("%lf",&l);fflush(stdin);
	  printf("\n give in the multiplier learning rate:- ");
	 scanf("%lf",&lm);fflush(stdin);
	  printf("\n give in the momentum factor:- ");
	 scanf("%lf",&p);fflush(stdin);
	 printf("\n give in the threshold factor:- ");
	 scanf("%lf",&th);fflush(stdin);
	  printf("\n give in the multiplication factor:- ");
	 scanf("%lf",&mul);fflush(stdin);
	 printf("do you want the data to be normalised:-");
	 scanf("%c",&norm);fflush(stdin);
	return;
      }

      void dlwzero()
      {
      int i,j,k;
	 for(i=1;i<=hid[0];i++)
	 {
	  for(j=star;j<=hid[i+1];j++)
	  { if(i==hid[0] && j==0) continue;
	   for(k=star;k<=hid[i];k++)
	   {
	   delw[i][j][k]=0.0;
	   }}}
	  for(i=star;i<=hid[1];i++)
	  {
	   for(j=star;j<=dim;j++)
	   {
	   delw[0][i][j]=0.0;
	  }}
	  return;
       }

       void outzero()
       {
       int i,j;
           for(i=1;i<=hid[0]+1;i++)
	   {
	    for(j=star;j<=hid[i];j++)
	    { if(i==hid[0]+1 && j==0) continue;
	    out[i][j]=0.0;
	    }
	   }
	 return;
       }

	void error()
	{
	 int i,j;
	 FILE *filer;
	 double error1;
	      count=0;averror=0.0;
	   filer=fopen(file1,"r");
	  while(!feof(filer))
	 { count++;
	 for(i=1;i<=dim;i++)
	 {
	   fscanf(filer,"%lf",&xvec[i]);
	   /*xvec[i]=(xvec[i]-maxmin[0])/(maxmin[1]-maxmin[0]);*/
	   if(norm!='n')  xvec[i]= xvec[i]/maxmin[1];
	 }
	 for(i=1;i<=class_no;i++)
	   fscanf(filer,"%lf",&t[i]);
	  valel();
	   averror+=err();
	 }
	  averror=averror/((double)count);
	  if(cc=='n')
	  printf("\naverror=%lf",averror);
	  fclose(filer);
	  return;
     }

     void train()
  {
      FILE *filerr;
      double averror1,er;
       int i,j,k,p1,x1,y1;
       double l1;
       FILE *filer;
     averror1=averror;
     if(ck!='y')i1=0;
     p1=0;l1=l;
	while(i1 < n && averror > err1)
	{
	  i1++;
	  if(cc=='n' && (i1%gap==0 || i1==n || i1==1))
	  {
	  printf("\n i1=%d",i1);
	  printf("averror=%lf",averror);
	  }
	  filer=fopen(file1,"r");
	  if(l > 0.3 && i1 > n/10)
	  {
	  if(averror > averror1)
	  {p1++;
	  if(p1 > 0)
	  { p1=0;
	   l=l-l1/(9.0*((double)n)/10.0);
	    }
	   }else p1=0;
	 }
	 if(l < 0.3) l=0.3;
	   averror1=averror;

	/*  printf("\n l=%lf l1=%lf",l,l1);*/
	/*  filerr=fopen("learning.dat","w");*/
/*	  fprintf(filerr,"%lf",l);*/
/*	  fclose(filerr);*/
	 while(!feof(filer))
	 {
	   for(i=1;i<=dim;i++)
	   {
	   fscanf(filer,"%lf",&xvec[i]);
/*	   xvec[i] = (xvec[i]-maxmin[0])/(maxmin[1]-maxmin[0]);*/
	    if(norm!='n') xvec[i]= xvec[i]/maxmin[1];
	   }
            for(i=1;i<=class_no;i++)
	   fscanf(filer,"%lf",&t[i]);
	   valel();
	     balance();
	 }  /*the while eof file ends*/
	 fclose(filer);
	 error();
	/* printwt();*/
       } 
	return;
   }
       void printwt()
       {
	 int i,j,k;
	 FILE *filer;
	 filer=fopen(file2,"w");
	 for(i=star;i<=hid[1];i++)
	 {
	  for(j=star;j<=dim;j++)
	  fprintf(filer,"%lf ",w[0][i][j]);
	  fprintf(filer,"\n");
	 }
	 fprintf(filer,"\n");
	 for(i=1;i<=hid[0];i++)
	 {
	  for(j=star;j<=hid[i+1];j++)
	  {if(i==hid[0] && j==0) continue;
	   for(k=1;k<=hid[i];k++)
	   fprintf(filer,"%lf ",w[i][j][k]);
	   fprintf(filer,"\n");
	  }
	  fprintf(filer,"\n");
	}
	  fclose(filer);
	  return;

      }

void valel()
  {
   int i,j,k;
   double xvec1[maxdim];
   for(i=1;i<=hid[0]+1;i++)
   {
    for(j=star;j<=hid[i];j++)
    { if(i==hid[0]+1 && j==0) continue;
    out[i][j]=0.0;
    }
   }
   for(i=1;i<=dim;i++)
   xvec1[i]=xvec[i]*(1.0/(1.0 + exp(-1.0*mult[i])));

   for(i=star;i<=hid[1];i++)
   {
    for(j=star;j<=dim;j++)
    {
    out[1][i]=out[1][i]+w[0][i][j]*xvec1[j];
    }
    out[1][i]=1.0/(1.0+exp(-1.0*mul*(out[1][i]-th)));
   }
   for(i=1;i<=hid[0];i++)
   {
    for(j=star;j<=hid[i+1];j++)
    {if(i==hid[0]+1 && j==0) continue;
     for(k=star;k<=hid[i];k++)
     {
     out[i+1][j]=out[i+1][j]+out[i][k]*w[i][j][k];
     }
     out[i+1][j]=1.0/(1.0+exp(-1.0*mul*(out[i+1][j]-th)));
    }}
    return;
 }


     double err()
	  {
       int i;double error1=0.0;
       for(i=1;i<=class_no;i++)
	error1+=(t[i]-out[pos][i])*(t[i]-out[pos][i]);
      return(error1);
     }


  void balance()
   {
    int i,j,k;
    double derout[maxhid+2][maxnur+1],del[maxhid+2][maxnur+1];
    for(i=1;i<=hid[0]+1;i++)
    {
    for(j=star;j<=hid[i];j++)
    {
    if(i==hid[0]+1 && j==0) continue;
       del[i][j]=0.0;
    }}

    for(i=1;i<=dim;i++)
    delmult[i]=0.0;

    for(i=1;i<=hid[0]+1;i++)
     {
      for(j=star;j<=hid[i];j++)
      {if(i==hid[0]+1 && j==0) continue;
       derout[i][j]=0.0;
     }}

     /****calculating derivatives for hidden layers and output layer***/


     for(i=1;i<=hid[0]+1;i++)
     {
      for(j=star;j<=hid[i];j++)
      {if(i==hid[0]+1 && j==0) continue;
       derout[i][j]=mul*out[i][j]*(1.0-out[i][j]);
     }}

     /****calculating the deltas of the output layer*******/


     for(i=1;i<=class_no;i++)
     {
      del[hid[0]+1][i]=1.0*derout[hid[0]+1][i]*(t[i]-out[hid[0]+1][i]);
     }

     /***calculating deltas for all hidden layers *****/

     for(i=hid[0];i>=1;i--)
      {
       for(k=star;k<=hid[i];k++)
       {
       for(j=star;j<=hid[i+1];j++)
       {if(i==hid[0] && j==0) continue;
       del[i][k]=del[i][k]+del[i+1][j]*w[i][j][k];
       }
        del[i][k]=1.0*derout[i][k]*del[i][k];
       }
     }

     /***balancing weights from output layer to last but one****/

     for(i=hid[0];i>=1;i--)
     {
      for(j=star;j<=hid[i+1];j++)
      { if(i==hid[0] && j==0) continue;
       for(k=star;k<=hid[i];k++)
       {
	delw[i][j][k]=p*delw[i][j][k]+(1.0-p)*del[i+1][j]*out[i][k];
	w[i][j][k]=l*delw[i][j][k]+w[i][j][k];
	}
       }
      }

      /****balancing for the weights from input to 1 hidden layer*****/

      for(i=star;i<=hid[1];i++)
      {
       for(j=star;j<=dim;j++)
       {
	delw[0][i][j]=p*delw[0][i][j]+(1.0-p)*del[1][i]*xvec[j];
	w[0][i][j]=l*delw[0][i][j]+w[0][i][j];
       }
       }
      for(j=1;j<=dim;j++)
      {
       for(i=1;i<=hid[1];i++)
       {
       delmult[j]+=del[1][i]*w[0][i][j];
       }
       delmult[j]=delmult[j]*(1.0 - (1.0/(1.0 + exp(-1.0*mult[j]))))*(1.0/(1.0 + exp(-1.0*mult[j])))*xvec[j];
       mult[j]+=lm*delmult[j];
       }
	  return;
   }

   void counter()
   {
    int i,corr=0,corr1=0,numerr=0;
    double out1;
    FILE *filer;
    filer=fopen(file1,"r");
    while(!feof(filer))
	 {
	  for(i=1;i<=dim;i++)
	  {
	  fscanf(filer,"%lf",&xvec[i]);
	 /* xvec[i] = (xvec[i]-maxmin[0])/(maxmin[1]-maxmin[0]);*/
	    if(norm!='n') xvec[i]= xvec[i]/maxmin[1];
	  }
	  for(i=1;i<=class_no;i++)
	  fscanf(filer,"%lf",&t[i]);
	  for(i=1;i<=class_no;i++)
	  if(t[i]==1.0) corr=i;
	  valel();
	  out1=out[hid[0]+1][1];
	  corr1=1;
	  for(i=2;i<=class_no;i++)
	  {
	  if(out[hid[0]+1][i] > out1) {out1=out[hid[0]+1][i];corr1=i;}
	  }
	  if(corr1!=corr) numerr++;
	  out1=0.00;
	 } fclose(filer);
       printf("no. of points missclass1fied=%d\n",numerr);

       for(i=1;i<=dim;i++)
       printf("%lf ",mult[i]);
       return;
     }

     void test()
     {
     int nn;
     printf("do you want to continue?:-");
     scanf("%c",&ck);fflush(stdin);
     if(ck=='n') exit(0);
     printf("how many ittrn more:-");
     scanf("%d",&nn);fflush(stdin);
     n=i1+nn;
     train();
     counter();
     test();
     }

    void multinit()
    {
    int i;
    for(i=1;i<=dim;i++)
    mult[i]=upper;
    }

